/**
 * 封装接口调用（HTTP 请求、MQTT 消息）维护公共数据
 * 将接口调用、MQTT 消息、以及本应放置于后端但暂时在前端实现了的逻辑统一封装成一个服务层，提供给界面层使用。
 * 这样做了之后，界面层将完全不用再关心接口、MQTT 消息的实现细节，只进行业务上的处理。
 *
 * 所有的业务行为可分为两种：
 * - action       主动触发操作，获取结果（API 调用；MQTT 发送消息，接收反馈消息）
 * - observable   接收数据或通知
 *
 * 封装原则：
 * 业务逻辑尽可能封装在服务层，使界面层仅包含“根据界面交互需要”而进行的处理。
 * 例如一个 computed 数据，如果是基于业务上的定义，那就放在服务层；而如果是为了方便界面显示，或者基于界面设计而进行的字符串格式化等，则放在界面层。
 *
 * 注意实现：
 * 1. observable 多次被订阅内部逻辑会运行多次，subject 多次被订阅内部逻辑只运行一次，因此尽量用 subject
 *
 * 2. 对于 map() 出来的 flag 类的值，用 distinctUntilChanged() 保证 map 出来的值没变时不会重复触发监听者
 *
 * 3. 区分 wxid 和 ownerWxid 两个词，不要混用。
 *    - 业务主体是“企业微信”时，其 id 为 wxid
 *    - 业务主体是企业微信的“联系人”时，若要提供对应企业微信的 id，名称应为 ownerWxid。因为这个联系人自己的 id 也可以称作一种 wxid，要避免混淆。
 *
 * 4. 每个大模块应把其他各子模块的类型定义等内容统一导出出来。这样一方面便于批量引入，同时也避免了把过多内部细节暴露在外面。
 *
 * 代码规范：
 * 1. service 代码按顺序实现如下部分：
 *   - 依赖定义（定义成 private 的）
 *   - 属性定义
 *   - 服务注册、初始化行为
 *   - 方法定义
 */
import { Service } from '@gnlab/utils'
import registerGlobal from '@gnlab/utils/env-browser/global'

import { AppInfo } from './app-info'
import { Auth } from './auth'
import { Chat } from './contact-chat'
import { ExternalTransfers, Externals, Groups, Internals, Notices } from './contact-types'
import { Contacts } from './contacts'
import { Container } from './container'
import { Features } from './features'
import { MQTT } from './mqtt'
import { NetLog } from './net-log'
import { Qywxs } from './qywxs'
import { Resources } from './resources'
import { SCRM } from './scrm'
import { SDKHost } from './sdk-host'
import { Utils } from './utils'

export type Services = {
  scrm: SCRM
  auth: Auth
  mqtt: MQTT
  sdkHost: SDKHost
  utils: Utils
  netlog: NetLog
  appInfo: AppInfo
  features: Features
  resources: Resources
  container: Container
  qywxs: Qywxs
  contacts: Contacts
  externals: Externals
  transfers: ExternalTransfers
  groups: Groups
  internals: Internals
  notices: Notices
  chat: Chat
}

export function initServices() {
  const inited = Service.initServices({
    scrm: new SCRM(),
    auth: new Auth(),
    mqtt: new MQTT(),
    sdkHost: new SDKHost(),
    utils: new Utils(),
    netlog: new NetLog(),
    appInfo: new AppInfo(),
    features: new Features(),
    resources: new Resources(),
    container: new Container(),
    qywxs: new Qywxs(),
    contacts: new Contacts(),
    externals: new Externals(),
    transfers: new ExternalTransfers(),
    groups: new Groups(),
    internals: new Internals(),
    notices: new Notices(),
    chat: new Chat(),
  })
  Object.assign(services, inited)
}

const services = {} as Services
registerGlobal('services', services)
export default services
